﻿using HDS.Common.Helper;
using HDS.Data;
using HDS.IService.Master;
using HDS.Model;
using HDS.Model.Entity.Master;
using HDS.Model.Entity.View;
using HDS.SupplierApi.Core.Entity;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace HDS.Service.Master
{
    public class SupplierHotelService : ISupplierHotelService
    {
        private MasterDbContext db = new MasterDbContext();

        public async Task<SupplierHotel> GetHotel(string supplier, string supplierHotelId)
        {
            return await db.SupplierHotel.GetSingleAsync(e => e.Supplier.Equals(supplier) && e.SupplierHotelId.Equals(supplierHotelId));
        }

        public async Task<VSupplierHotel> GetVHotel(string supplier, string supplierHotelId)
        {
            return await db.Db.Queryable<SupplierHotel, MappingHotel, SupplierHotelMark>((sh, mh, shm) => new JoinQueryInfos(
                     JoinType.Left, sh.Supplier.Equals(mh.Supplier) && sh.SupplierHotelId.Equals(mh.SupplierHotelId) && mh.MappingStatus,
                     JoinType.Left, sh.Supplier.Equals(shm.Supplier) && sh.SupplierHotelId.Equals(shm.SupplierHotelId)
                ))
                .WhereIF(!string.IsNullOrEmpty(supplier), sh => sh.Supplier.Equals(supplier))
                .WhereIF(!string.IsNullOrEmpty(supplierHotelId), sh => sh.SupplierHotelId.Equals(supplierHotelId))
                .Select<VSupplierHotel>().FirstAsync();
        }

        public async Task<DataPagingModel<VSupplierHotel>> GetHotelList(int pageIndex, int pageSize, string supplier = "", string supplierHotelId = "", int? hotelId = null, bool? isAvail = null, bool? isTop = null, bool? isMapping = null, decimal? hotelStar = null, string hotelNameEn = "", string hotelNameCn = "", string countryName = "", string cityName = "")
        {
            RefAsync<int> total = 0;
            var rows = await db.Db.Queryable<SupplierHotel, MappingHotel, SupplierHotelMark>((sh, mh, shm) => new JoinQueryInfos(
                     JoinType.Left, sh.Supplier.Equals(mh.Supplier) && sh.SupplierHotelId.Equals(mh.SupplierHotelId) && mh.MappingStatus,
                     JoinType.Left, sh.Supplier.Equals(shm.Supplier) && sh.SupplierHotelId.Equals(shm.SupplierHotelId)
                ))
                .WhereIF(!string.IsNullOrEmpty(supplier), sh => sh.Supplier.Equals(supplier))
                .WhereIF(!string.IsNullOrEmpty(supplierHotelId), sh => sh.SupplierHotelId.Equals(supplierHotelId))
                .WhereIF(hotelId.HasValue, (sh,mh) => mh.HotelId.Equals(hotelId))
                .WhereIF(isAvail.HasValue && isAvail.Value, (sh, mh, shm) => shm.IsAvail)
                .WhereIF(isAvail.HasValue && !isAvail.Value, (sh, mh, shm) => !shm.IsAvail || string.IsNullOrEmpty(shm.SupplierHotelId))
                .WhereIF(isTop.HasValue && isTop.Value, (sh, mh, shm) => shm.SupplierTop > 0)
                .WhereIF(isTop.HasValue && !isTop.Value, (sh, mh, shm) => shm.SupplierTop <= 0 || string.IsNullOrEmpty(shm.SupplierHotelId))
                .WhereIF(isMapping.HasValue && isMapping.Value, (sh, mh, shm) => mh.HotelId > 0)
                .WhereIF(isMapping.HasValue && !isMapping.Value, (sh, mh, shm) => string.IsNullOrEmpty(mh.SupplierHotelId))
                .WhereIF(hotelStar.HasValue, (sh, mh, shm) => sh.HotelStar == hotelStar)
                .WhereIF(!string.IsNullOrEmpty(hotelNameEn), sh => sh.HotelNameEn.Contains(hotelNameEn))
                .WhereIF(!string.IsNullOrEmpty(hotelNameCn), sh => sh.HotelNameCn.Contains(hotelNameCn))
                .WhereIF(!string.IsNullOrEmpty(countryName), sh => sh.CountryName.Contains(countryName))
                .WhereIF(!string.IsNullOrEmpty(cityName), sh => sh.CityName.Contains(cityName))
                .OrderBy(sh => sh.Id, OrderByType.Desc)
                .Select<VSupplierHotel>()
                .ToPageListAsync(pageIndex, pageSize, total);

            return new DataPagingModel<VSupplierHotel>
            {
                PageIndex = pageIndex,
                PageSize = pageSize,
                PageTotal = (total.Value + pageSize - 1) / pageSize,
                Total = total.Value,
                Rows = rows
            };
        }

        public async Task UpdateHotel(SupplierHotel entity)
        {
            var old = await db.SupplierHotel.GetSingleAsync(e => e.Supplier.Equals(entity.Supplier) && e.SupplierHotelId.Equals(entity.SupplierHotelId));
            if (old == null)
            {
                await db.SupplierHotel.InsertAsync(entity);
            }
            else
            {
                await db.Db.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).Where(e => e.Supplier.Equals(entity.Supplier) && e.SupplierHotelId.Equals(entity.SupplierHotelId)).ExecuteCommandAsync();
            }
        }


        public async Task<SupplierRoom> GetRoom(string supplier, string supplierHotelId, string supplierRoomId)
        {
            return await db.SupplierRoom.GetSingleAsync(e => e.Supplier.Equals(supplier) && e.SupplierHotelId.Equals(supplierHotelId) && e.SupplierRoomId.Equals(supplierRoomId));
        }

        public async Task<DataPagingModel<SupplierRoom>> GetRoomList(int pageIndex, int pageSize, string supplier = "", string supplierHotelId = "", int? hotelId = null)
        {
            RefAsync<int> total = 0;
            List<SupplierRoom> rows;
            if (!hotelId.HasValue)
            {
                rows = await db.Db.Queryable<SupplierRoom>()
                    .WhereIF(!string.IsNullOrEmpty(supplier), e => e.Supplier.Equals(supplier))
                    .WhereIF(!string.IsNullOrEmpty(supplierHotelId), e => e.SupplierHotelId.Equals(supplierHotelId))
                    .OrderBy(sh => sh.Id, OrderByType.Desc)
                    .ToPageListAsync(pageIndex, pageSize, total);
            }
            else
            {
                rows = await db.Db.Queryable<SupplierRoom, MappingHotel>((sh, mh) => new JoinQueryInfos(
                     JoinType.Inner, sh.Supplier.Equals(mh.Supplier) && sh.SupplierHotelId.Equals(mh.SupplierHotelId) && mh.MappingStatus && mh.HotelId.Equals(hotelId)
                ))
                .OrderBy((sh, mh) => sh.Id, OrderByType.Desc)
                .ToPageListAsync(pageIndex, pageSize, total);
            }

            return new DataPagingModel<SupplierRoom>
            {
                PageIndex = pageIndex,
                PageSize = pageSize,
                PageTotal = (total.Value + pageSize - 1) / pageSize,
                Total = total.Value,
                Rows = rows
            };
        }

        public async Task<List<SupplierRoom>> GetRoomList(string supplier, string supplierHotelId)
        {
            return await db.SupplierRoom.GetListAsync(e => e.Supplier.Equals(supplier) && e.SupplierHotelId.Equals(supplierHotelId));
        }

        public async Task AddRooms(string supplier, string supplierHotelId, List<SupplierRoom> supplierRoomList)
        {
            foreach (var room in supplierRoomList)
            {
                if (string.IsNullOrEmpty(room.SupplierRoomId) || string.IsNullOrEmpty(room.RoomNameEn))
                    continue;

                var old = await db.SupplierRoom.GetSingleAsync(e => e.Supplier.Equals(supplier) && e.SupplierHotelId.Equals(supplierHotelId) && e.SupplierRoomId.Equals(room.SupplierRoomId));
                if (old != null)
                {
                    if (!old.RoomNameEn.Equals(room.RoomNameEn)
                         || !old.RoomNameCn.Equals(room.RoomNameCn)
                         || !old.MaxOccupancy.Equals(room.MaxOccupancy)
                         || !old.RoomDesc.Equals(room.RoomDesc)
                         || !old.RoomStatus.Equals(room.RoomStatus)
                         || !old.ThirdPartyId.Equals(room.ThirdPartyId))
                    {
                        room.Id = old.Id;
                        db.Db.Updateable(room).Where(e => e.Supplier.Equals(supplier) && e.SupplierHotelId.Equals(supplierHotelId) && e.SupplierRoomId.Equals(room.SupplierRoomId)).AddQueue();
                    }
                }
                else
                {
                    db.Db.Insertable(room).AddQueue();
                }
            }
            await db.Db.SaveQueuesAsync();
        }

        public async Task AddRooms(List<SupplierRate> rateList)
        {
            if (rateList.IsEmpty())
                return;

            var supplierRoomList = new List<SupplierRoom>();
            foreach (var rate in rateList)
            {
                if (!supplierRoomList.Exists(e => e.Supplier.Equals(rate.Supplier) && e.SupplierHotelId.Equals(rate.HotelId) && e.SupplierRoomId.Equals(rate.RoomId)))
                {
                    supplierRoomList.Add(new SupplierRoom
                    {
                        Id = 0,
                        Supplier = rate.Supplier,
                        SupplierHotelId = rate.HotelId,
                        SupplierRoomId = rate.RoomId,
                        ThirdPartyId = rate.ThirdPartyId,
                        MaxOccupancy = GetPaxNumByRoomName(rate.RoomName),
                        RoomNameEn = rate.RoomName,
                        RoomNameCn = "",
                        RoomDesc = "",
                        RoomStatus = true,
                        UpdatedTime = DateTime.Now
                    });
                }
            }

            foreach (var room in supplierRoomList)
            {
                var old = await db.SupplierRoom.GetSingleAsync(e => e.Supplier.Equals(room.Supplier) && e.SupplierHotelId.Equals(room.SupplierHotelId) && e.SupplierRoomId.Equals(room.SupplierRoomId));
                if (old == null)
                {
                    db.Db.Insertable(room).AddQueue();
                }
            }
            await db.Db.SaveQueuesAsync();
        }

        private int GetPaxNumByRoomName(string roomNameEn)
        {
            roomNameEn = roomNameEn.ToLower();
            if (roomNameEn.IndexOf("single") >= 0 || roomNameEn.IndexOf("sole use") >= 0)
            {
                return 1;
            }

            if (roomNameEn.IndexOf("triple") >= 0)
            {
                return 3;
            }

            if (roomNameEn.IndexOf("quadruple") >= 0)
            {
                return 4;
            }

            if (roomNameEn.IndexOf("two bedroom") >= 0)
            {
                return 4;
            }

            if (roomNameEn.IndexOf("three bedroom") >= 0)
            {
                return 6;
            }

            if (roomNameEn.IndexOf("four bedroom") >= 0)
            {
                return 8;
            }

            return 3;
        }

        public async Task<bool> DeleteRoom(string supplier, string supplierHotelId, string supplierRoomId)
        {
            await db.MappingRoom.DeleteAsync(e => e.Supplier.Equals(supplier) && e.SupplierHotelId.Equals(supplierHotelId) && e.SupplierRoomId.Equals(supplierRoomId));
            return await db.SupplierRoom.UpdateAsync(e => new SupplierRoom { RoomStatus = false }, e => e.Supplier.Equals(supplier) && e.SupplierHotelId.Equals(supplierHotelId) && e.SupplierRoomId.Equals(supplierRoomId) && e.RoomStatus);
        }

        public async Task<bool> RestoreRoom(string supplier, string supplierHotelId, string supplierRoomId)
        {
            return await db.SupplierRoom.UpdateAsync(e => new SupplierRoom { RoomStatus = true }, e => e.Supplier.Equals(supplier) && e.SupplierHotelId.Equals(supplierHotelId) && e.SupplierRoomId.Equals(supplierRoomId) && !e.RoomStatus);
        }


        public async Task<SupplierHotelMark> GetMark(string supplier, string supplierHotelId)
        {
            return await db.SupplierHotelMark.GetSingleAsync(e => e.Supplier.Equals(supplier) && e.SupplierHotelId.Equals(supplierHotelId));
        }
    }
}
